package itsur.arquitecturas.pipeandfilter;

import java.util.Stack;
import java.util.regex.Pattern;

public class Prueba {
	// String regex = "\\d{5}( (or|and) \\d{5})*";

	// curso [(and|or curso)*]
	public static void main(String[] args) {
		Prueba p = new Prueba();

		String cursosACumplir = "( 12333 or 13444 ) and 13222";
		String cursosDelAlumno = "12333 13222";

		if (p.validarExpresion(cursosACumplir)) {
			System.out.println(p.validarAlumno(cursosACumplir, cursosDelAlumno));
		}else
			System.out.println("Expresion de cursos a evaluar invalida.");
	}

	/**
	 * Contar cantidad de ocurrencias de una cadena en otra.
	 * 
	 * @param cadenaOrignal
	 * @param cadenaBuscada
	 * @return
	 */
	public int countOccurrences(String cadenaOrignal, String cadenaBuscada) {
		int count = 0;
		int index = 0;

		while ((index = cadenaOrignal.indexOf(cadenaBuscada, index)) != -1) {
			++index;
			++count;
		}
		return count;
	}

	/**
	 * Validar que la expresion escrita sea valida de acuerdo al patron esperado
	 * y que se encuentre debidamente balanceada.
	 * 
	 * @param expresion
	 * @return
	 */
	private boolean validarExpresion(String expresion) {
		String regex = "(\\( )*\\d{5}( (or|and) (\\( )*\\d{5}( \\))*)*( \\))*";
		boolean validacion = false;
		validacion = Pattern.matches(regex, expresion);

		validacion = validacion
				&& (countOccurrences(expresion, "(") == countOccurrences(
						expresion, ")"));

		return validacion;
	}

	public boolean validarAlumno(String cursosACumplir, String cursosDelAlumno) {

		String[] items = cursosACumplir.split(" ");
		Stack<String> valueStack = new Stack<String>();
		Stack<String> operatorStack = new Stack<String>();
		String peekItem;

		for (String item : items) {
			if (item.equals("and") || item.equals("or")) {

				while (!operatorStack.empty()
						&& (operatorStack.peek().length() >= item.length())) {
					peekItem = operatorStack.pop();
					String leftItem = valueStack.pop();
					String rightItem = valueStack.pop();

					if (peekItem.equals("and")) {
						boolean temp = Boolean.parseBoolean(leftItem)
								&& Boolean.parseBoolean(rightItem);

						System.out.println("Evaluation: " + leftItem + " and "
								+ rightItem + " = " + String.valueOf(temp));
						valueStack.push(String.valueOf(temp));
					} else if (peekItem.equals("or")) {
						boolean temp = Boolean.parseBoolean(leftItem)
								|| Boolean.parseBoolean(rightItem);

						System.out.println("Evaluation: " + leftItem + " and "
								+ rightItem + " = " + String.valueOf(temp));
						valueStack.push(String.valueOf(temp));
					}
				}
				System.out.println("Push operator: " + item);
				operatorStack.push(item);

			} else if (item.equals("(")) { // Si es parentesis izquierdo
				// guardarlo en el operator stack
				operatorStack.push("(");
			} else if (item.equals(")")) {// Si es parentesis derecho realizar
				// lo siguiente...
				while (!operatorStack.peek().equals("(")) {// mientras el
					// simbolo en la
					// cima de
					// operatorStack no
					// sea parentesis
					// izquierdo

					peekItem = operatorStack.pop();
					String leftItem = valueStack.pop();
					String rightItem = valueStack.pop();

					if (peekItem.equals("and")) {
						boolean temp = Boolean.parseBoolean(leftItem)
								&& Boolean.parseBoolean(rightItem);

						System.out.println("Evaluation: " + leftItem + " and "
								+ rightItem + " = " + String.valueOf(temp));
						valueStack.push(String.valueOf(temp));
					} else if (peekItem.equals("or")) {
						boolean temp = Boolean.parseBoolean(leftItem)
								|| Boolean.parseBoolean(rightItem);

						System.out.println("Evaluation: " + leftItem + " and "
								+ rightItem + " = " + String.valueOf(temp));
						valueStack.push(String.valueOf(temp));
					}

				}
				operatorStack.pop(); // Al final sacar el parentisis del
				// operatorStack

			} else {
				// si el item es un curso evaluar si el alumno tiene ese
				// curso...
				if (cursosDelAlumno.contains(item)) {// ...Si el alumno tiene el
					// curso guardar true en
					// valueStack
					System.out.println("Push value: true");
					valueStack.push("true");
				} else {// ...Si el alumno no tiene el curso guardar false en
					// valueStack
					System.out.println("Push value: false");
					valueStack.push("false");
				}
			}
		}

		while (!operatorStack.empty()) {
			peekItem = operatorStack.pop();
			String leftItem = valueStack.pop();
			String rightItem = valueStack.pop();

			if (peekItem.equals("and")) {
				boolean temp = Boolean.parseBoolean(leftItem)
						&& Boolean.parseBoolean(rightItem);

				System.out.println("Evaluation: " + leftItem + " and "
						+ rightItem + " = " + String.valueOf(temp));
				valueStack.push(String.valueOf(temp));
			} else if (peekItem.equals("or")) {
				boolean temp = Boolean.parseBoolean(leftItem)
						|| Boolean.parseBoolean(rightItem);

				System.out.println("Evaluation: " + leftItem + " and "
						+ rightItem + " = " + String.valueOf(temp));
				valueStack.push(String.valueOf(temp));
			}
		}

		for (String s : valueStack) {
			System.out.println("final: " + s);
		}

		// Solamente debio haber quedado un elemento en la pila.
		return Boolean.parseBoolean(valueStack.peek());
	}

}
